Türkçe

TypeScript dizin imzalarına kapsamlı bir kılavuz. Uluslararası yazılım geliştirme için dinamik özellik erişimi, tür güvenliği ve esnek veri yapıları sağlar.

TypeScript Dizin İmzaları: Dinamik Özellik Erişimi Uzmanlığı

Yazılım geliştirme dünyasında, esneklik ve tür güvenliği genellikle zıt güçler olarak görülür. JavaScript'in bir üst kümesi olan TypeScript, bu boşluğu zarif bir şekilde kapatarak her ikisini de geliştiren özellikler sunar. Bu güçlü özelliklerden biri de dizin imzalarıdır. Bu kapsamlı kılavuz, TypeScript dizin imzalarının karmaşıklıklarını derinlemesine inceler ve sağlam tür denetimini korurken dinamik özellik erişimini nasıl sağladıklarını açıklar. Bu, özellikle çeşitli kaynaklardan ve formatlardan gelen verilerle küresel olarak etkileşim kuran uygulamalar için çok önemlidir.

TypeScript Dizin İmzaları Nelerdir?

Dizin imzaları, özellik adlarını önceden bilmediğinizde veya özellik adları dinamik olarak belirlendiğinde bir nesnedeki özelliklerin türlerini tanımlamanın bir yolunu sağlar. Onları, "Bu nesne bu belirli türde herhangi sayıda özelliğe sahip olabilir" demenin bir yolu olarak düşünün. Bir arayüz veya tür takma adı içinde aşağıdaki sözdizimi kullanılarak bildirilirler:


interface MyInterface {
  [index: string]: number;
}

Bu örnekte, [index: string]: number dizin imzasıdır. Bileşenleri parçalayalım:

Bu nedenle, MyInterface herhangi bir string özelliğinin (örneğin, "age", "count", "user123") bir sayı değerine sahip olması gereken bir nesneyi tanımlar. Bu, tam anahtarların önceden bilinmediği verilerle uğraşırken esneklik sağlar; bu, harici API'leri veya kullanıcı tarafından oluşturulan içeriği içeren senaryolarda yaygındır.

Neden Dizin İmzaları Kullanılır?

Dizin imzaları çeşitli senaryolarda çok değerlidir. İşte bazı temel faydaları:

Dizin İmzaları Uygulamada: Pratik Örnekler

Dizin imzalarının gücünü göstermek için bazı pratik örnekleri inceleyelim.

Örnek 1: String Sözlüğünü Temsil Etme

Anahtarların ülke kodları (örneğin, "US", "CA", "GB") ve değerlerin ülke adları olduğu bir sözlüğü temsil etmeniz gerektiğini hayal edin. Türü tanımlamak için bir dizin imzası kullanabilirsiniz:


interface CountryDictionary {
  [code: string]: string; // Anahtar ülke kodu (string), değer ülke adı (string)
}

const countries: CountryDictionary = {
  "US": "United States",
  "CA": "Canada",
  "GB": "United Kingdom",
  "DE": "Germany"
};

console.log(countries["US"]); // Çıktı: United States

// Hata: 'number' türü 'string' türüne atanamaz.
// countries["FR"] = 123; 

Bu örnek, dizin imzasının tüm değerlerin string olması gerektiğini nasıl zorladığını gösterir. Bir ülke koduna bir sayı atamaya çalışmak bir tür hatasıyla sonuçlanacaktır.

Örnek 2: API Yanıtlarını İşleme

Kullanıcı profillerini döndüren bir API düşünün. API, kullanıcıdan kullanıcıya değişen özel alanlar içerebilir. Bu özel alanları temsil etmek için bir dizin imzası kullanabilirsiniz:


interface UserProfile {
  id: number;
  name: string;
  email: string;
  [key: string]: any; // Herhangi bir türde başka herhangi bir string özelliğine izin ver
}

const user: UserProfile = {
  id: 123,
  name: "Alice",
  email: "alice@example.com",
  customField1: "Value 1",
  customField2: 42,
};

console.log(user.name); // Çıktı: Alice
console.log(user.customField1); // Çıktı: Value 1

Bu durumda, [key: string]: any dizin imzası, UserProfile arayüzünün herhangi bir türde herhangi sayıda ek string özelliğine sahip olmasına izin verir. Bu, id, name ve email özelliklerinin doğru şekilde yazılmasını sağlarken esneklik sağlar. Ancak, `any` kullanırken dikkatli olunmalıdır, çünkü bu tür güvenliğini azaltır. Mümkünse daha spesifik bir tür kullanmayı düşünün.

Örnek 3: Dinamik Yapılandırmayı Doğrulama

Harici bir kaynaktan yüklenen bir yapılandırma nesneniz olduğunu varsayalım. Yapılandırma değerlerinin beklenen türlere uygun olduğunu doğrulamak için dizin imzalarını kullanabilirsiniz:


interface Config {
  [key: string]: string | number | boolean;
}

const config: Config = {
  apiUrl: "https://api.example.com",
  timeout: 5000,
  debugMode: true,
};

function validateConfig(config: Config): void {
  if (typeof config.timeout !== 'number') {
    console.error("Invalid timeout value");
  }
  // Daha fazla doğrulama...
}

validateConfig(config);

Burada, dizin imzası yapılandırma değerlerinin string, sayı veya boolean olmasına izin verir. validateConfig işlevi daha sonra değerlerin amaçlanan kullanımları için geçerli olduğundan emin olmak için ek kontroller gerçekleştirebilir.

String ve Sayı Dizin İmzaları

Daha önce belirtildiği gibi, TypeScript hem string hem de number dizin imzalarını destekler. Farklılıkları anlamak, bunları etkili bir şekilde kullanmak için çok önemlidir.

String Dizin İmzaları

String dizin imzaları, özelliklere string anahtarlarını kullanarak erişmenizi sağlar. Bu, en yaygın dizin imzası türüdür ve özellik adlarının string olduğu nesneleri temsil etmek için uygundur.


interface StringDictionary {
  [key: string]: any;
}

const data: StringDictionary = {
  name: "John",
  age: 30,
  city: "New York"
};

console.log(data["name"]); // Çıktı: John

Sayı Dizin İmzaları

Sayı dizin imzaları, özelliklere sayı anahtarlarını kullanarak erişmenizi sağlar. Bu, genellikle dizileri veya dizi benzeri nesneleri temsil etmek için kullanılır. TypeScript'te, bir sayı dizin imzası tanımlarsanız, sayısal indeksleyicinin türü, string indeksleyicinin türünün bir alt türü olmalıdır.


interface NumberArray {
  [index: number]: string;
}

const myArray: NumberArray = [
  "apple",
  "banana",
  "cherry"
];

console.log(myArray[0]); // Çıktı: apple

Önemli Not: Sayı dizin imzalarını kullanırken, TypeScript özelliklere erişirken sayıları otomatik olarak stringlere dönüştürür. Bu, myArray[0]'ın myArray["0"]'a eşdeğer olduğu anlamına gelir.

Gelişmiş Dizin İmzası Teknikleri

Temel bilgilerin ötesinde, daha da güçlü ve esnek tür tanımları oluşturmak için dizin imzalarını diğer TypeScript özellikleriyle birleştirebilirsiniz.

Dizin İmzalarını Belirli Özelliklerle Birleştirme

Bir arayüzde veya tür takma adında dizin imzalarını açıkça tanımlanmış özelliklerle birleştirebilirsiniz. Bu, dinamik olarak eklenen özelliklerle birlikte gerekli özellikleri tanımlamanıza olanak tanır.


interface Product {
  id: number;
  name: string;
  price: number;
  [key: string]: any; // Herhangi bir türde ek özelliklere izin ver
}

const product: Product = {
  id: 123,
  name: "Laptop",
  price: 999.99,
  description: "High-performance laptop",
  warranty: "2 years"
};

Bu örnekte, Product arayüzü, id, name ve price özelliklerini gerektirirken, dizin imzası aracılığıyla ek özelliklere de izin verir.

Jenerikleri Dizin İmzalarıyla Kullanma

Jenerikler, farklı türlerle çalışabilen yeniden kullanılabilir tür tanımları oluşturmanın bir yolunu sağlar. Jenerik veri yapıları oluşturmak için jenerikleri dizin imzalarıyla kullanabilirsiniz.


interface Dictionary {
  [key: string]: T;
}

const stringDictionary: Dictionary = {
  name: "John",
  city: "New York"
};

const numberDictionary: Dictionary = {
  age: 30,
  count: 100
};

Burada, Dictionary arayüzü, farklı değer türlerine sahip sözlükler oluşturmanıza olanak tanıyan jenerik bir tür tanımıdır. Bu, çeşitli veri türleri için aynı dizin imzası tanımını tekrarlamaktan kaçınır.

Birim Türleriyle Dizin İmzaları

Özelliklerin farklı türlere sahip olmasına izin vermek için birim türlerini dizin imzalarıyla kullanabilirsiniz. Bu, birden çok olası türe sahip olabilen verilerle uğraşırken kullanışlıdır.


interface MixedData {
  [key: string]: string | number | boolean;
}

const mixedData: MixedData = {
  name: "John",
  age: 30,
  isActive: true
};

Bu örnekte, MixedData arayüzü özelliklerin string, sayı veya boolean olmasına izin verir.

Literal Türleriyle Dizin İmzaları

Dizinin olası değerlerini kısıtlamak için literal türlerini kullanabilirsiniz. Bu, izin verilen belirli bir özellik adı kümesini zorlamak istediğinizde kullanışlı olabilir.


type AllowedKeys = "name" | "age" | "city";

interface RestrictedData {
  [key in AllowedKeys]: string | number;
}

const restrictedData: RestrictedData = {
  name: "John",
  age: 30,
  city: "New York"
};

Bu örnek, özellik adlarını "name", "age" ve "city" ile kısıtlamak için bir literal türü AllowedKeys kullanır. Bu, genel bir `string` dizinine kıyasla daha katı tür denetimi sağlar.

`Record` Yardımcı Türünü Kullanma

TypeScript, temelde belirli bir anahtar türü ve değer türü ile bir dizin imzası tanımlamak için kısa bir yol olan `Record` adlı yerleşik bir yardımcı tür sağlar.


// Şuna eşdeğer: { [key: string]: number }
const recordExample: Record = {
  a: 1,
  b: 2,
  c: 3
};

// Şuna eşdeğer: { [key in 'x' | 'y']: boolean }
const xyExample: Record<'x' | 'y', boolean> = {
  x: true,
  y: false
};

`Record` türü, temel bir sözlük benzeri yapıya ihtiyacınız olduğunda sözdizimini basitleştirir ve okunabilirliği artırır.

Eşlenmiş Türleri Dizin İmzalarıyla Kullanma

Eşlenmiş türler, mevcut bir türün özelliklerini dönüştürmenize olanak tanır. Mevcut olanlara dayalı yeni türler oluşturmak için dizin imzalarıyla birlikte kullanılabilirler.


interface Person {
  name: string;
  age: number;
  email?: string; // İsteğe bağlı özellik
}

// Kişi'nin tüm özelliklerini gerekli yap
type RequiredPerson = { [K in keyof Person]-?: Person[K] };

const requiredPerson: RequiredPerson = {
  name: "Alice",
  age: 30,   // E-posta artık gerekli.
  email: "alice@example.com" 
};

Bu örnekte, RequiredPerson türü, Person arayüzünün tüm özelliklerini gerekli yapmak için bir dizin imzasıyla eşlenmiş bir tür kullanır. `-?` e-posta özelliğinden isteğe bağlı değiştiriciyi kaldırır.

Dizin İmzalarını Kullanmak İçin En İyi Uygulamalar

Dizin imzaları büyük esneklik sunarken, tür güvenliğini ve kod netliğini korumak için bunları dikkatli bir şekilde kullanmak önemlidir. İşte bazı en iyi uygulamalar:

Yaygın Tuzaklar ve Bunlardan Nasıl Kaçınılır

Dizin imzaları hakkında sağlam bir anlayışa sahip olsanız bile, bazı yaygın tuzaklara düşmek kolaydır. İşte nelere dikkat etmeniz gerektiği:

Uluslararasılaştırma ve Yerelleştirme Hususları

Küresel bir kitle için yazılım geliştirirken, uluslararasılaştırmayı (i18n) ve yerelleştirmeyi (l10n) dikkate almak çok önemlidir. Dizin imzaları, yerelleştirilmiş verilerin işlenmesinde rol oynayabilir.

Örnek: Yerelleştirilmiş Metin

Anahtarların dil kodları (örneğin, "en", "fr", "de") ve değerlerin karşılık gelen metin stringleri olduğu bir yerelleştirilmiş metin stringleri koleksiyonunu temsil etmek için dizin imzalarını kullanabilirsiniz.


interface LocalizedText {
  [languageCode: string]: string;
}

const localizedGreeting: LocalizedText = {
  "en": "Hello",
  "fr": "Bonjour",
  "de": "Hallo"
};

function getGreeting(languageCode: string): string {
  return localizedGreeting[languageCode] || "Hello"; // Bulunamazsa varsayılan olarak İngilizce'ye ayarla
}

console.log(getGreeting("fr")); // Çıktı: Bonjour
console.log(getGreeting("es")); // Çıktı: Hello (varsayılan)

Bu örnek, dizin imzalarının bir dil koduna göre yerelleştirilmiş metni depolamak ve almak için nasıl kullanılabileceğini gösterir. İstenen dil bulunamazsa varsayılan bir değer sağlanır.

Sonuç

TypeScript dizin imzaları, dinamik verilerle çalışmak ve esnek tür tanımları oluşturmak için güçlü bir araçtır. Bu kılavuzda özetlenen kavramları ve en iyi uygulamaları anlayarak, TypeScript kodunuzun tür güvenliğini ve uyarlanabilirliğini artırmak için dizin imzalarından yararlanabilirsiniz. Kod kalitesini korumak için öncelikle belirli ve net olmaya öncelik vererek bunları dikkatli bir şekilde kullanmayı unutmayın. TypeScript yolculuğunuza devam ederken, dizin imzalarını keşfetmek, şüphesiz küresel bir kitle için sağlam ve ölçeklenebilir uygulamalar oluşturmak için yeni olanakların kilidini açacaktır. Dizin imzalarında uzmanlaşarak, projelerinizi daha sağlam ve çeşitli veri kaynaklarına ve gelişen gereksinimlere daha uyarlanabilir hale getirerek daha etkileyici, bakımı kolay ve tür açısından güvenli kod yazabilirsiniz. Daha iyi yazılımlar oluşturmak için TypeScript'in ve dizin imzalarının gücünü kucaklayın.